/*************************************************************
 * @file      tones.c 
 * @brief     提示音
 *
 *
 * @version    v0.0
 * @author     xieyoub
 * @data       2017/06/12
 *************************************************************/
 
 #include "tones.h"
 #include "flash.h"
 #include "stdio.h"
 #include "timer.h"
 #include "audio_mgr.h"		
#include <uCOS-II\Source\ucos_ii.h>

 
 /** @addtogroup  提示音
  * 
  *  @{
  */


static uint8_t tempBuf[512];


/**< 播放设备     */
PlayDev playDev;

/**< 播放数据缓存     */
AudioSource audioSource[AUDIO_SOURCE_MAX_NUM]={0};
static uint8_t audioSouCursor = 0;
/**< 打断待播数据链表     */
AudioSourceList audioSourceList[AUDIO_SOURCE_MAX_NUM]={0};
static uint8_t audioSourceListIndex = 0;
static AudioSourceList* pHead = NULL;
static AudioSourceList* pTail = NULL;

/**< 消息队列     */
static AudioMessage	audioMessage[AUDIO_MSG_MAX_NUM]={0};
static uint8_t msgInCursor = 0;
static uint8_t msgOutCursor = 0;


/** @brief 		取出待播放的音频源信息
  * 
  * @param  
  * @return 
  * @note
  */
bool AudioSourceFIFOOut(AudioSource* source)
{
	if(pHead!=NULL){
		//source = pHead->source;
		memcpy(source,pHead->source,sizeof(AudioSource));
		if(pHead->pNext!=NULL){
			pHead = pHead->pNext;
		}
		else{
			pHead = NULL;
			pTail = NULL;
		}
		
		return TRUE;
	}
	return FALSE;
}


/** @brief 		存待播放的音频源信息
  * 
  * @param  
  * @return 
  * @note
  */
void AudioSourceFIFOIn(AudioSource* source)
{
	AudioSourceList* pCurrent = NULL;
	audioSourceList[audioSourceListIndex].source = source;
	//memcpy(audioSourceList[audioSourceListIndex].source,source,sizeof(AudioSource));
	if(!pHead){
		pHead = &audioSourceList[audioSourceListIndex];
		pTail = pHead;
	}
	else{
		//printf("list not empty!\n");
		/**< 非按键类的音频添加到缓冲区尾     */
		if(source->audioType != AUDIO_TYPE_KEY_NORMAL){
			pTail->pNext = &audioSourceList[audioSourceListIndex];
			audioSourceList[audioSourceListIndex].pPre = pTail;
			pTail = &audioSourceList[audioSourceListIndex];
			pTail->pNext = NULL;
		}
		/**< 按键类的音频插到非按键音频的前面     */
		else{
			pCurrent = pHead;
			
			while(pCurrent){
				if(pCurrent->source->audioType!=AUDIO_TYPE_KEY_NORMAL){
					audioSourceList[audioSourceListIndex].pNext  = pCurrent;
					audioSourceList[audioSourceListIndex].pPre   = pCurrent->pPre;
					pCurrent->pPre->pNext  = &audioSourceList[audioSourceListIndex];
					pCurrent->pPre  = &audioSourceList[audioSourceListIndex];
					break;
				}
				
				pCurrent = pCurrent->pNext;
			}
			
		}
			
	}

	audioSourceListIndex = (audioSourceListIndex+1) % AUDIO_SOURCE_MAX_NUM;
}

/**	@brief 	消息队列中加入一条消息
  * 
  * @param  type	消息类型
	* @param	id		消息ID
	*	@param	p			消息p参数
  * @return void
  * @note
  */
void AudioPostMessage(uint16_t type,uint16_t id,uintptr_t p)
{
#ifdef USE_CRITICAL_WHEN_POST 
    
#if OS_CRITICAL_METHOD == 3u	 
	 OS_CPU_SR cpu_sr  = 0u;
#endif	
 	OS_ENTER_CRITICAL();	
#endif
	
    audioMessage[msgInCursor].type = type;
    audioMessage[msgInCursor].id = id;
    audioMessage[msgInCursor].p = p;
    msgInCursor = (msgInCursor+1) % AUDIO_MSG_MAX_NUM;

//    if(msgInCursor == msgOutCursor){
//        printf("Audio msg queue gg\n");
//    }
    
#ifdef USE_CRITICAL_WHEN_POST 	
 	OS_EXIT_CRITICAL();	
#endif    
}


/**	@brief 	 停止播放
  * 
  * @param  
  * @return 
  * @note
  */
void AudioDevStop()
{
#ifdef DAC_TIMER_OUT	
	TIM_Cmd(LPC_TIM1,DISABLE);
#endif	
	pHead = NULL;
	pTail = NULL;
	playDev.playEnd = 1;
	playDev.playState = PLAY_DEV_STATE_IDLE;
}


/**	@brief 	窥探消息队列中是否存在消息
  * 
  * @return  有消息返回true,否则false
  * @note
  */
bool	AudioPeekMessage(AudioMessage* pMsg)
{
	if(msgOutCursor!=msgInCursor){
		memcpy(pMsg,&(audioMessage[msgOutCursor]),sizeof(AudioMessage));
		msgOutCursor = (msgOutCursor+1) % AUDIO_MSG_MAX_NUM;
#ifndef NO_PEEK_PROC        
		return true;
#endif        
	}
	return false;
}

/** @brief 		音频播放
  * 
  * @param  	type	声源类型
  * @return 	void
  * @note
  */
void AudioPlay(AudioType type)
{
//	printf("AudioPlay\n");
	audioSource[audioSouCursor].audioType = type;
	AudioPostMessage(USER_MSG_AUDIO_PLAY,type,(uintptr_t)&(audioSource[audioSouCursor]));
	audioSouCursor = (audioSouCursor+1) % AUDIO_SOURCE_MAX_NUM;
}

void AudioStopPlay()
{
//	printf("AudioStopPlay\n");
	AudioPostMessage(USER_MSG_AUDIO_STOP,0,0);
}


/** @brief 	获取数据长度
  * 
  * @param  address	 数据所在FLASH中的地址
  * @return 
  * @note
  */
uint32_t AudioGetDataLength(uint32_t address)
{
	uint8_t buf[4]={0};
	uint32_t temp;
	uint32_t length = 0;
	/**< WAVE文件头的4~43字节为数据长度     */
	SPI_Flash_Read(buf,address+40,4);

	length = ((uint32_t)buf[3])<<24;
	length |= ((uint32_t)buf[2])<<16;
	length |= ((uint32_t)buf[1])<<8;
	length |= buf[0];
	
	return length;
}


/** @brief 		WAVE 文件确认
  * 
  * @param  	address  数据地址
  * @return 	WAVE 返回 true 否则返回 false
  * @note
  */
bool isWaveFile(uint32_t address)
{
	uint8_t buf[4]={0};
	
	SPI_Flash_Read(buf,address+8,4);
	
	
	if(buf[0]=='W'&&buf[1]=='A'&&buf[2]=='V'&&buf[3]=='E'){
		return true;
	}
	
	return false;
}


/** @brief 	从FLASH 中获取音频数据
  * 
  * @param  
  * @return 
  * @note
  */
#ifdef DAC_TIMER_OUT
void	TonesRead(uint8_t* buf,uint32_t address)
{
	int index=0;
	uint8_t temp = 0;
	
	
	/**< 剩余的数据大小超过512     */
	if(playDev.curSource->remainSize>=READ_SIZE){
		
		/**< 读取512字节数据     */
		SPI_Flash_Read(buf,address,READ_SIZE);
		/**< DAC 数据大小     */
		playDev.curSize = READ_SIZE;
		
		/**< 数据存储地址偏移     */
		playDev.curSource->address += READ_SIZE;
		/**< 剩余数据量     */
		playDev.curSource->remainSize -= READ_SIZE;
	}
	/**< 剩余的数据量不足512字节     */
	else{
		/**< 读取剩余全部数据     */
		SPI_Flash_Read(buf,address,playDev.curSource->remainSize);
		/**< DAC 数据大小     */
		playDev.curSize =  playDev.curSource->remainSize;
		
		/**< 剩余数据量     */
		playDev.curSource->remainSize = 0;
	}
	
	temp = buf[playDev.curSize-1];
	index = playDev.curSize;
	//剩余的buf 填充最后一个数据
	for(;index<READ_SIZE;index++)
		buf[index] = temp;
	
	playDev.curSize = READ_SIZE;
}
#else
void	TonesRead(uint32_t* buf,uint32_t address)
{
	int index=0;
	uint32_t temp = 0;
	
	memset(tempBuf,0,sizeof(tempBuf));
	memset(buf,0,READ_SIZE*4);
	
	/**< 剩余的数据大小超过512     */
	if(playDev.curSource->remainSize>=READ_SIZE){
		
		/**< 读取512字节数据     */
		SPI_Flash_Read(tempBuf,address,READ_SIZE);
		/**< DAC 数据大小     */
		playDev.curSize = READ_SIZE;
		
		/**< 数据存储地址偏移     */
		playDev.curSource->address += READ_SIZE;
		/**< 剩余数据量     */
		playDev.curSource->remainSize -= READ_SIZE;
	}
	/**< 剩余的数据量不足512字节     */
	else{
		/**< 读取剩余全部数据     */
		SPI_Flash_Read(tempBuf,address,playDev.curSource->remainSize);
		/**< DAC 数据大小     */
		playDev.curSize =  playDev.curSource->remainSize;
		
		/**< 剩余数据量     */
		playDev.curSource->remainSize = 0;
	}

    temp = 0;
	/**< DAC输出寄存器的低6位无效，将数据左移6位     */
	for(index=0;index<playDev.curSize;index++){
		buf[index] = tempBuf[index];
        
        if(playDev.curSource->audioType==AUDIO_TYPE_KEY_NORMAL){
            if(temp<44){
                buf[index] = 0x3f;
                temp++;
            }
            else if(temp<44*2){
                buf[index] = 0;
                temp++;
            }
            
            if(temp>=44*2){
                temp = 0;
            }
            
        }
        buf[index] <<= 6;
	}
	temp = buf[index-1];
	//剩余的buf 填充最后一个数据
	for(;index<READ_SIZE;index++)
		buf[index] = temp;
	
	playDev.curSize = READ_SIZE;
}
#endif


/** @brief 		播放源信息初始化
  * 
  * @param  
  * @return 
  * @note
  */
bool PlaySourceInit(AudioSource* source)
{
	switch(source->audioType){
		case AUDIO_TYPE_KEY_NORMAL:
			source->address = FLASH_ADDRESS_AUDIO_KEY_NORMAL;
			break;
		
		case AUDIO_TYPE_KEY_UNNORMAL:
			source->address = FLASH_ADDRESS_AUDIO_KEY_UNNORMAL;
			break;
		
		case AUDIO_TYPE_CALL:
			source->address = FLASH_ADDRESS_AUDIO_CALL;
			break;
		
		case AUDIO_TYPE_PICK_UP:
			source->address = FLASH_ADDRESS_AUDIO_PICKUP;
			break;
		
		case AUDIO_TYPE_TALK_END:
			source->address = FLASH_ADDRESS_AUDIO_TALK_END;
			break;
		
		case AUDIO_TYPE_NO_ANSWER:
			source->address = FLASH_ADDRESS_AUDIO_NOANSWER;
			break;
		
		case AUDIO_TYPE_CALL_FAIL:
			source->address = FLASH_ADDRESS_AUDIO_CALL_FAIL;
			break;
		
		case AUDIO_TYPE_CALLER:
			source->address = FLASH_ADDRESS_AUDIO_CALLER;
			break;
		
		case AUDIO_TYPE_TALKING_CALL:
			source->address = FLASH_ADDRESS_AUDIO_TALKINGE_CALL;
			break;
		
		default:
			return false ;
			break;
	}
	if(!isWaveFile(source->address)){
//		printf("flash file err \n");
		return false;
	}
	
	//获取音频数据长度
	source->totalSize = AudioGetDataLength(source->address);
	source->address += 44;	//前44字节为文件头
	source->remainSize = source->totalSize;
	return true;
}




/** @brief 	播放设备初始化
  * 
  * @param  
  * @return 
  * @note
  */
void PlayDevInit(AudioSource* source)
{
	
	Audio_TurnOn(SpkOnwer_Tone);
	
	OSTimeDlyHMSM(0,0,0,60);
#ifdef DAC_TIMER_OUT	
	TIM_ResetCounter(LPC_TIM1);
	TIM_Cmd(LPC_TIM1,DISABLE);
#endif	
	/**< 播放状态初始化     */
	playDev.playState = PLAY_DEV_STATE_BUSY;
	playDev.playEnd = 0;
	/**< 播放数据源信息初始化     */
	playDev.curSource = source;
	/**< 播放通道初始化     */
	playDev.nCh = 0;
	/**< 获取播放数据     */
	TonesRead(playDev.buf1,playDev.curSource->address);
	/**< 开始播放     */
	if(playDev.curSize>0)
#ifdef DAC_TIMER_OUT
		playDev.dacOutIndex = 0;
		TIM_Cmd(LPC_TIM1,ENABLE);
#else	
		DmaChannel0Init(playDev.buf1,playDev.curSize);
#endif
	
	playDev.nCh = 1; 
	/**< 缓存下次要输出的数据     */
	TonesRead(playDev.buf2,playDev.curSource->address);
	
}




/** @brief 	提示音任务
  * 
  * @param  
  * @note
  */
void TonesTask(void *p_arg)
{
	uint8_t playType=1;
	
	AudioMessage msg;
	
	//Play Test
	
	//Timer1Init(2000000);
	//Audio_TurnOn(SpkOnwer_Tone);
	//Timer1Init(1000000/DAC_RATE);
	AudioPlay(playType);
	
	while(1)
	{
        static uint16_t RunningCnt  = 0;
		while(AudioPeekMessage(&msg)){
			
			/*---------------------------开始播放一段音频----------------------------*/
			if(msg.type==USER_MSG_AUDIO_PLAY){
//				printf("audio play! audio type:%d\n",msg.id);
				/**< 正在播放    */
				if(playDev.playState==PLAY_DEV_STATE_BUSY){
//					printf("state busy\n");
					/**< 音频类型判断,为按键音时则打断之前的音频,等按键音播放结束后再继续播放     */
					if(msg.id==AUDIO_TYPE_KEY_NORMAL || msg.id==AUDIO_TYPE_KEY_UNNORMAL){
//						printf("read audio is key\n");
						if(playDev.curSource->audioType!=AUDIO_TYPE_KEY_NORMAL
							&&playDev.curSource->audioType!=AUDIO_TYPE_KEY_UNNORMAL){
//								printf("interrupt\n");
							AudioSourceFIFOIn(playDev.curSource);
							if(!PlaySourceInit((AudioSource*)msg.p))
								break;
							
							playDev.curSource = (AudioSource*)msg.p;
								
#ifdef DAC_TIMER_OUT								
							PlayDevInit(playDev.curSource);	
								//TIM_Cmd(LPC_TIM1,DISABLE);
#else 								
							playDev.playState = PLAY_DEV_STATE_INTER;
#endif								
						}
						/**< 冲突，按键音未播放完再次收到按键音消息     */
						else{
							//AudioSourceFIFOIn(playDev.curSource);
//							printf("inter err!");
							//AudioStopPlay();
						}
					}
					/**< 非按键音消息     */
					else{
//						printf("read is not key\n");
						/**< 当前正在播放按键音时，将音频加入队列，等待按键音播放完再播放     */
						if(playDev.curSource->audioType==AUDIO_TYPE_KEY_NORMAL || playDev.curSource->audioType==AUDIO_TYPE_KEY_UNNORMAL){
							AudioSourceFIFOIn((AudioSource*)msg.p);
							//printf("cur audio is key!");
						}
						/**< 非按键音未播放完时收到播放非按键音：停止当前播放     */
						else{
//							printf("other audio inter!\n");
							//AudioStopPlay();		
							//AudioSourceFIFOIn((AudioSource*)msg.p);
							if(!PlaySourceInit((AudioSource*)msg.p))
								break;
							playDev.curSource = (AudioSource*)msg.p;
							playDev.playState = PLAY_DEV_STATE_INTER;
						}
					}
					
				}
				/**< 非播放状态     */
				else if(playDev.playState == PLAY_DEV_STATE_IDLE){
//					printf("state idle\n");
					//初始化播放源数据信息
					if(!PlaySourceInit((AudioSource*)msg.p))
						break;
					PlayDevInit((AudioSource*)msg.p);
				}
				/**< 被打断状态     */
				else if(playDev.playState == PLAY_DEV_STATE_INTER){
//					printf("state inter\n");
					if(playDev.curSource->audioType!=AUDIO_TYPE_KEY_NORMAL
							&&playDev.curSource->audioType!=AUDIO_TYPE_KEY_UNNORMAL){
						AudioSourceFIFOIn((AudioSource*)msg.p);
					}
					//AudioStopPlay();
				}
			}
			/*---------------------------播放512个字节结束----------------------------*/
			else if(msg.type==USER_MSG_AUDIO_DACOUT_END){
				//printf("DMA END:%d\n",d);
				/**< 当前音频被打断     */
				if(playDev.playState == PLAY_DEV_STATE_INTER){
//					printf("dma end , dispose inter audio\n");
					//TIM_Cmd(LPC_TIM1,DISABLE);
					PlayDevInit(playDev.curSource);
				}
				else if(playDev.playState == PLAY_DEV_STATE_BUSY){
					//当前源数据全部播放结束
					if(playDev.playEnd==1){
						playDev.playState = PLAY_DEV_STATE_IDLE;
#ifdef	DAC_TIMER_OUT						
						TIM_Cmd(LPC_TIM1,DISABLE);
#endif						
		
						/**< 待播放列表中获取下一个音频源信息   */
						if(AudioSourceFIFOOut(playDev.curSource)){
//							printf("play audio form Source List!\n");
							PlayDevInit(playDev.curSource);
						}
						else{
                            
//							printf("playEnd!\n");
							playType++;
							if(playType==10)
								playType = 1;
                            
                            OSTimeDlyHMSM(0, 0, 1, 0);
							AudioPlay(playType);
							//如果非按键音是否要重复播放？ 预留
//							if(playDev.curSource->audioType==AUDIO_TYPE_CALL
//								||playDev.curSource->audioType==AUDIO_TYPE_TALK_END
//								||playDev.curSource->audioType==AUDIO_TYPE_NO_ANSWER
//								||playDev.curSource->audioType==AUDIO_TYPE_CALL_FAIL
//								||playDev.curSource->audioType==AUDIO_TYPE_CALLER
//								||playDev.curSource->audioType==AUDIO_TYPE_TALKING_CALL){
//							
//								AudioPlay(playDev.curSource->audioType);
//								//d=0;
//							}
//							else{
//								Audio_TurnOff(SpkOnwer_Tone);
//							}
						}
					}
					else{
						/**< 输出BUF1数据，缓存下一段数据到BUF2    */
						if(playDev.nCh==0){
							//printf("ch:1%d\n",playDev.curSize);
							playDev.nCh = 1;
							DmaChannel0Init(playDev.buf1,playDev.curSize);
							if(playDev.curSource->remainSize>0){
								TonesRead(playDev.buf2,playDev.curSource->address);
							}
							else{
								playDev.playEnd = 1;
							}
						}
						
						/**< 输出BUF2数据，缓存下一段数据到BUF1     */
						else if(playDev.nCh==1){
							playDev.nCh = 0;
							DmaChannel0Init(playDev.buf2,playDev.curSize);
							if(playDev.curSource->remainSize>0){
								TonesRead(playDev.buf1,playDev.curSource->address);
							}
							else{
								playDev.playEnd = 1;
							}
						}
					}
				}
				else if(playDev.playState == PLAY_DEV_STATE_IDLE){
					//TIM_Cmd(LPC_TIM1,DISABLE);
//					printf("IDLE err\n");
					if(AudioSourceFIFOOut(playDev.curSource)){
						PlayDevInit(playDev.curSource);
					}
				}
			}
			//停止播放
			else if(msg.type == USER_MSG_AUDIO_STOP){
//				printf("audio stop\n");
				AudioDevStop();
			}
			
		}
		
		OSTimeDlyHMSM(0, 0, 0, 10);
        
        RunningCnt++;
        if(RunningCnt > 2000){
            RunningCnt   = 0;
            //printf("Tones task running...\n");
        }
	}
}



/** @} */
